import { Client } from "./mod.ts";

/**
 * User represents a API user.
 */
export interface User {
  id: number;
  username: string; // LEGACY [Gogs 1.0]: kept for backward compatibility
  login: string;
  full_name: string;
  email: string;
  avatar_url: string;
}

/**
 * AccessToken represents a API access token.
 */
export interface AccessToken {
  name: string;
  sha1: string;
}

/**
 * CreateAccessTokenOption represents options for creating an access token
 */
export interface CreateAccessTokenOption {
  name: string;
}

/**
 * Email represents an email address that belongs to a user
 */
export interface Email {
  email: string;
  verified: boolean;
  primary: boolean;
}

/**
 * CreateEmailOption represents options for creating an email
 */
export interface CreateEmailOption {
  emails: string[];
}

/**
 * PublicKey represents a user's public key
 */
export interface PublicKey {
  id: number;
  key: string;
  url?: string;
  title?: string;
  created_at?: string;
}

/**
 * CreateKeyOption represents options for creating a public key
 */
export interface CreateKeyOption {
  title: string;
  key: string;
}

/**
 * Utility function to encode basic auth credentials
 */
export function basicAuthEncode(user: string, pass: string): string {
  return btoa(`${user}:${pass}`);
}

/**
 * User API endpoints
 */
export class UserAPI {
  constructor(private client: Client) {}

  /**
   * Get user information by username
   */
  async getUser(username: string): Promise<User> {
    return await this.client.doRequest<User>("GET", `/users/${username}`);
  }

  /**
   * Get current authenticated user
   */
  async getSelf(): Promise<User> {
    return await this.client.doRequest<User>("GET", "/user");
  }

  // Access Token API

  /**
   * List all access tokens of a user
   */
  async listAccessTokens(user: string, pass: string): Promise<AccessToken[]> {
    return await this.client.doRequest<AccessToken[]>("GET", `/users/${user}/tokens`, {
      "Authorization": `Basic ${basicAuthEncode(user, pass)}`
    });
  }

  /**
   * Create a new access token for a user
   */
  async createAccessToken(user: string, pass: string, options: CreateAccessTokenOption): Promise<AccessToken> {
    return await this.client.doRequest<AccessToken>("POST", `/users/${user}/tokens`, {
      "Content-Type": "application/json",
      "Authorization": `Basic ${basicAuthEncode(user, pass)}`
    }, options);
  }

  // Email API

  /**
   * List all email addresses of authenticated user
   */
  async listEmails(): Promise<Email[]> {
    return await this.client.doRequest<Email[]>("GET", "/user/emails");
  }

  /**
   * Add email addresses to authenticated user
   */
  async addEmail(options: CreateEmailOption): Promise<Email[]> {
    return await this.client.doRequest<Email[]>("POST", "/user/emails", {
      "Content-Type": "application/json"
    }, options);
  }

  /**
   * Delete email addresses from authenticated user
   */
  async deleteEmail(options: CreateEmailOption): Promise<void> {
    await this.client.doRequest<void>("DELETE", "/user/emails", {
      "Content-Type": "application/json"
    }, options);
  }

  // Follower API

  /**
   * List followers of authenticated user
   */
  async listMyFollowers(page = 1): Promise<User[]> {
    return await this.client.doRequest<User[]>("GET", `/user/followers?page=${page}`);
  }

  /**
   * List followers of a user
   */
  async listFollowers(username: string, page = 1): Promise<User[]> {
    return await this.client.doRequest<User[]>("GET", `/users/${username}/followers?page=${page}`);
  }

  /**
   * List users that authenticated user is following
   */
  async listMyFollowing(page = 1): Promise<User[]> {
    return await this.client.doRequest<User[]>("GET", `/user/following?page=${page}`);
  }

  /**
   * List users that a user is following
   */
  async listFollowing(username: string, page = 1): Promise<User[]> {
    return await this.client.doRequest<User[]>("GET", `/users/${username}/following?page=${page}`);
  }

  /**
   * Check if authenticated user is following a user
   */
  async isFollowing(target: string): Promise<boolean> {
    try {
      await this.client.doRequest<void>("GET", `/user/following/${target}`);
      return true;
    } catch (error) {
      return false;
    }
  }

  /**
   * Check if one user is following another user
   */
  async isUserFollowing(user: string, target: string): Promise<boolean> {
    try {
      await this.client.doRequest<void>("GET", `/users/${user}/following/${target}`);
      return true;
    } catch (error) {
      return false;
    }
  }

  /**
   * Follow a user
   */
  async follow(target: string): Promise<void> {
    await this.client.doRequest<void>("PUT", `/user/following/${target}`, {
      "Content-Type": "application/json"
    });
  }

  /**
   * Unfollow a user
   */
  async unfollow(target: string): Promise<void> {
    await this.client.doRequest<void>("DELETE", `/user/following/${target}`);
  }

  // Public Key API

  /**
   * List public keys of a user
   */
  async listPublicKeys(username: string): Promise<PublicKey[]> {
    return await this.client.doRequest<PublicKey[]>("GET", `/users/${username}/keys`);
  }

  /**
   * List public keys of authenticated user
   */
  async listMyPublicKeys(): Promise<PublicKey[]> {
    return await this.client.doRequest<PublicKey[]>("GET", "/user/keys");
  }

  /**
   * Get a public key by ID
   */
  async getPublicKey(keyID: number): Promise<PublicKey> {
    return await this.client.doRequest<PublicKey>("GET", `/user/keys/${keyID}`);
  }

  /**
   * Create a public key
   */
  async createPublicKey(options: CreateKeyOption): Promise<PublicKey> {
    return await this.client.doRequest<PublicKey>("POST", "/user/keys", {
      "Content-Type": "application/json"
    }, options);
  }

  /**
   * Delete a public key
   */
  async deletePublicKey(keyID: number): Promise<void> {
    await this.client.doRequest<void>("DELETE", `/user/keys/${keyID}`);
  }
} 